package com.xyzboom.compiler.fa

class NFA<T, K> {
    val nodeIn: NFANode<T, K>
    val nodeOut: NFANode<T, K>
    val allNodes: MutableSet<NFANode<T, K>>

    constructor(nodeIn: NFANode<T, K>, nodeOut: NFANode<T, K>) {
        this.nodeIn = nodeIn
        this.nodeOut = nodeOut
        this.allNodes = HashSet()
    }

    constructor(node: NFANode<T, K>) {
        nodeIn = node
        nodeOut = nodeIn
        this.allNodes = HashSet()
    }

    constructor(nodeIn: NFANode<T, K>, nodeOut: NFANode<T, K>, allNodes: MutableSet<NFANode<T, K>>) {
        this.nodeIn = nodeIn
        this.nodeOut = nodeOut
        this.allNodes = allNodes
    }

    /**
     * 重新将NFA的出口连接到指定节点，不重置对应的边
     */
    fun relinkToNodeOut(node: NFANode<T, K>) {
        for (entry in nodeOut.next) {
            entry.value.clear()
            entry.value.add(node)
        }
    }

    fun relinkNullToNodeOut(node: NFANode<T, K>) {
        nodeOut.next.clear()
        linkNullToNodeOut(node)
    }

    /**
     * 重新将NFA的出口连接到指定节点，重置对应的边
     */
    fun relinkEdgeToNodeOut(edge: FAEdge<K>, node: NFANode<T, K>) {
        nodeOut.next.clear()
        addLinkEdgeToNodeOut(edge, node)
    }

    /**
     * 在NFA的出口节点添加指定的边与指定的节点
     */
    fun addLinkEdgeToNodeOut(edge: FAEdge<K>, node: NFANode<T, K>) {
        nodeOut.next.getOrPut(edge) { HashSet() }.add(node)
    }

    fun linkNullToNodeOut(node: NFANode<T, K>) {
        nodeOut.next.getOrPut(null) { HashSet() }.add(node)
    }

    override fun toString(): String {
        return "NFA(${nodeIn.value}, ${nodeOut.value})"
    }
}